#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/poll.h>
#include <pthread.h>
#include <sys/epoll.h>

void *client_thread(void *arg) {
    int clientfd = *(int *)arg;
    while (1) {
        char buffer[128] = {0};
        int count = recv(clientfd, buffer, 128, 0);
        if (count == 0) {
            close(clientfd);
            break;
        }
        printf("recv:count:%d,buffer:%s\n", count, buffer);
        send(clientfd, buffer, count, 0);
    }
    close(clientfd);
}

int main() {
    // 0 stdin 1 stdout 2 stderr 
    int socketfd = socket(AF_INET, SOCK_STREAM, 0);
    
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(struct sockaddr_in));

    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(2048);

    if (bind(socketfd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr)) == -1) {
        perror("bind");
        return -1;
    }
    listen(socketfd, 10);
#if 0
    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(clientaddr);
    int clientfd = accept(socketfd, (struct sockaddr *)&clientaddr, &len);


#else
    #if 0
    while (1)
    {
        struct sockaddr_in clientaddr;
        socklen_t len = sizeof(clientaddr);
        int clientfd = accept(socketfd, (struct sockaddr *)&clientaddr, &len);

        pthread_t thid;
        pthread_create(&thid, NULL, client_thread, &clientfd);
    }
    #elif 0
    // select
    fd_set rfds, rset;
    FD_ZERO(&rfds);
    FD_SET(socketfd, &rfds);

    int maxfd = socketfd;
    while (1)
    {
        rset = rfds;  // rset 是用于内核态的， rfds是用于用户态的
        int nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
        if (FD_ISSET(socketfd, &rset)) {
            struct sockaddr_in clientaddr;
            socklen_t len = sizeof(clientaddr);
            int clientfd = accept(socketfd, (struct sockaddr *)&clientaddr, &len);
            printf("socketfd:%d\n", clientfd);
            FD_SET(clientfd, &rfds);
            maxfd = clientfd;
            printf("socketfd:%d,maxfd:%d\n", socketfd, maxfd);
        }
        
        int i = 0;
        for (i = socketfd + 1; i <= maxfd; i++) {
            if (FD_ISSET(i, &rset)) {
                char buffer[128] = {0};
                int count = recv(i, buffer, 128, 0);
                if (count == 0) {
                    FD_CLR(i, &rfds);
                    close(i);
                    break;
                }
                printf("recv:count:%d,buffer:%s\n", count, buffer);
                send(i, buffer, count, 0);
            }
        }
    }
    #elif 0
    struct pollfd fds[1024] = {0};
    fds[socketfd].fd = socketfd;
    fds[socketfd].events = POLLIN;
    int maxfd = socketfd;
    while (1) {
        int nready = poll(fds, maxfd + 1, -1);
        if (fds[socketfd].revents & POLLIN) {
            struct sockaddr_in clientaddr;
            socklen_t len = sizeof(clientaddr);
            int clientfd = accept(socketfd, (struct sockaddr *)&clientaddr, &len);
            fds[clientfd].fd = clientfd;
            fds[clientfd].events = POLLIN;
            maxfd = clientfd;
        }
        int i = 0;
        for (i = socketfd + 1; i <= maxfd; i++) {
            if (fds[i].revents & POLLIN) {
                char buffer[128] = {0};
                int count = recv(i, buffer, 128, 0);
                if (count == 0) {
                    fds[i].fd = -1;
                    fds[i].events = 0;
                    close(i);
                    continue;
                }
                printf("recv:count:%d,buffer:%s\n", count, buffer);
                send(i, buffer, count, 0);
            }
        }
    }
    #else
    int epfd = epoll_create(1);
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = socketfd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, socketfd, &ev);
    
    struct epoll_event events[1024] = {0};
    while (1) {
        int nready = epoll_wait(epfd, events, 1024, -1);
        
        int i = 0;
        for (i = 0; i < nready; i ++) {
            int connectfd = events[i].data.fd;
            if (socketfd == connectfd) {
                struct sockaddr_in clientaddr;
                socklen_t len = sizeof(clientaddr);
                int clientfd = accept(socketfd, (struct sockaddr *)&clientaddr, &len);
                ev.events = EPOLLIN;
                ev.data.fd = clientfd;
                epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev);
                printf("clientfd:%d\n", clientfd);
            } else if (events[i].events & EPOLLIN) {
                char buffer[128] = {0};
                int count = recv(connectfd, buffer, 128, 0);
                if (count == 0) {
                    epoll_ctl(epfd, EPOLL_CTL_DEL, connectfd, NULL);
                    close(connectfd);
                    continue;
                }
                printf("recv:count:%d,buffer:%s\n", count, buffer);
                send(connectfd, buffer, count, 0);
            }
        }
    }
    #endif
#endif
    getchar();
    close(socketfd);
    return 0;
}